package org.fjsei.yewu.payload;

import lombok.Getter;
import lombok.Setter;
import md.specialEqp.Eqp;
import md.specialEqp.fee.Charging;
import md.specialEqp.inspect.Detail;
import md.specialEqp.type.PipingUnit;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**自动计算收费，后端反馈给前端的信息：
 *GraphQL Mutation() 操作:可返回不是普通Object或者也不是简单数据类型的其它的复合组装类型的应答,和input类型相反的POJO。
 * */
@Getter
@Setter
public class CalcFeeResp {
    /**声明 须严肃对待的参数的标签名 ，重新校验和输入；否则收费计算有失公允性！。
     * 已经被认定为 合法的参数 不需要返回。
     * parms非空的: 若计算失败，不完整不可信。
     * */
    private List<String> parms=new ArrayList<>();
    //private String[]  parms;    //假如parms[]非空的，必然收费可能有问题。

    /**Mutation本身内部事务处理是同步等待的；可是返回给前端的应答结构体CalcFeeResp。它的数据可能是内省：异步，并发的，前后端缓存？。
     * */
    private Detail  bus;

    /**自动计算出来的 收费明细； 勉强拼凑 在一起：
     * 相当于Context作用； 但不准备作为GraphQL操作输出返回给前端。
     * */
    List<Charging>  fees=new ArrayList<>();
    /** 加快计算，管道单元计费专用：fees的变换形态，临时中转站 用。
     * 目标是每一个fee_code可直接关联，添加 管道单元 给 List<PipingUnit>  pipus;
     * 相当于Context作用； 但不准备作为GraphQL操作输出返回给前端。
     * */
    Map<String, Charging>  feemap= new HashMap<>();


    public void addFeeItem(String code, double amount, int fm) {
        addFeeItem(code, amount,  fm, null, null);
    }
    public void addFeeItem(String code, double amount, int fm, Double mnum) {
        addFeeItem(code, amount,  fm, mnum, null);
    }
    public void addFeeItem(String code, double amount, int fm, Double mnum,String memo) {
        Charging charging=new Charging();
        //charging.setDetail(bus);
        charging.setCode(code);
        charging.setAmount(amount);
        charging.setFm((byte)fm);
        charging.setMnum(mnum);
        charging.setManual(false);
        if(StringUtils.hasText(memo))   charging.setMemo(memo);
        //chargingRepository.save(charging);
        fees.add(charging);
    }
    //精简版本
  //  public void useBase(String code,  int amount) {
  //      addFeeItem(code, (double) amount,1, null);
  //  }
    //fee_mod=1的收费
    public void useBase(String code,  double amount) {
        addFeeItem(code,  amount,1, null);
    }
    public void useBase(String code,  double amount, String memo) {
        addFeeItem(code, amount, 1, null, memo);
    }
    //附加最少收费限制
    public void useBase(String code,  double amount, int minAmount) {
        if(amount<minAmount)    addFeeItem(code, (double) minAmount,1, null);
        else   addFeeItem(code, (double) amount,1, null);
    }
    //有分叉基准收费数+标准/单位 * 乘数的收费。  参数baseSum可能<0的！
    public void useBase(String code,double baseSum, double unitAmount,double mnum) {
        addFeeItem(code, baseSum + unitAmount*mnum,1, mnum);
    }
    public void useBase(String code,double baseSum, double unitAmount,double mnum, String memo) {
        addFeeItem(code, baseSum + unitAmount*mnum,1, mnum, memo);
    }
    //直接模块归并  通用工具性质函数
    //设备 单台工程造价，最少也要：
    public double 校验造价(Eqp eqp, Detail bus, double minMoney, double minCcost){
        if(null==eqp.getMoney() || eqp.getMoney()<minMoney)   parms.add("money");
        if(null==bus.getCcost() || bus.getCcost()<minCcost)   parms.add("ccost");
        if(null!=eqp.getMoney() && null!=bus.getCcost())
            return  bus.getCcost() + eqp.getMoney();
        else    return 0;
    }
    //mod1收费合计；@必须保障：mod1:收费全都是自动计算的；都是新生成的，而非数据库中遗留的mod1收费项目。
    public double  addUpMod1fee(){
        List<Double>  mod1it= fees.stream().filter(item ->
                (item.getFm()==(byte) 1)
        ).map(Charging::getAmount).collect(Collectors.toList());
        return mod1it.stream().reduce(Double::sum).orElseGet(()-> (double) 0);
    }
    //改造修理设备价+ 单台工程造价，最少也要：
    public double use改造修理造价(Detail bus, double minMreprc, double minCcost){
        if(null==bus.getMreprc() || bus.getMreprc()<minMreprc)   parms.add("mreprc");
        if(null==bus.getCcost() || bus.getCcost()<minCcost)   parms.add("ccost");
        if(null!=bus.getMreprc() && null!=bus.getCcost())
            return  bus.getCcost() + bus.getMreprc();
        else    return 0;
    }
    /**管道单元添加收费项；【特别】：和其它设备不同=需要指定关联单元！
     * 每一个管道单元需要聚合处理： 已经存在的收费代码要合并，合并收费乘数，合并总金额，前提条件是：fee_code代码一样,收费标准一样！
     * */
    public void addPipingFee(PipingUnit punit,String code, double basePrice) {
        if(null!=punit && null!=punit.getLeng() && punit.getLeng()>0) {         //punit合格性检查在派工时间决定。
            //函数式List<PipingUnit> doorLst = feemap.computeIfAbsent(code, k -> new ArrayList<PipingUnit>());  doorLst.add(punit);
            Charging charging = feemap.computeIfAbsent(code, k -> new Charging());
            if (!code.equals(charging.getCode())) {
                charging.setCode(code);
                charging.setFm((byte) 1);        //附属于管道单元的收费清单：都是自动计算mod1。
                charging.setManual(false);
                charging.setMnum(punit.getLeng().doubleValue());         //乘数都是 管道单元长度。  基数标准单位都是==一样的。
                charging.setAmount(basePrice * punit.getLeng());
                fees.add(charging);
                List<PipingUnit>  pipus=new ArrayList<>();
                pipus.add(punit);
                charging.setPipus(pipus);
            } else {        //已经存在的收费项，不是新生成
                charging.setMnum(punit.getLeng() + charging.getMnum());
                //charging.setMemo(memo);    //管道单元默认收费参数，没必要指引报错，前端自己应该负责提醒收费参数可能有问题的。
                charging.setAmount(basePrice * punit.getLeng() + charging.getAmount());
                charging.getPipus().add(punit);
            }
        }
    }
}

